package com.example.yx.demo23;

import org.apache.tomcat.jni.Address;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.validation.DataBinder;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.ServletRequestParameterPropertyValues;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TestServletDataBinder {

    public static void main(String[] args) throws Exception {
//        MyBean target = new MyBean();
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setParameter("birthday","1999|01|02");//日期格式,无法识别
        request.setParameter("address.name","西安");//“.”的取值，可以读取到属性的属性
//        request.setParameter("c","1999/03/04");
        User target = new User();


        // "1.用工厂，无转换功能“
//        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(null,null);
//        WebDataBinder binder = binderFactory.createBinder(new ServletWebRequest(request), target, "user");

        // "2.用@InitBinder转换"      本质上是利用了PropertyEditorRegister 和PropertyEditor的功能
            //收集用@InitBinder标注的方法信息
//        InvocableHandlerMethod method
//                = new InvocableHandlerMethod(new Controller(), Controller.class.getMethod("aaa", WebDataBinder.class));
//        List<InvocableHandlerMethod> list = new ArrayList<>();
//        list.add(method);
//            //收集好的信息传给绑定工厂
//        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(list,null);
            //回调被标注的方法并扩展
        // "3.用 ConversionService转换 "
//        FormattingConversionService service = new FormattingConversionService();
//        service.addFormatter(new MyDateFormatter("用 ConversionService 扩展转换功能"));
//        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
//        initializer.setConversionService(service);
//        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(null, initializer);
        // "4. 同时加了 @InitBinder 和 ConversionService "
//        InvocableHandlerMethod method
//                = new InvocableHandlerMethod(new Controller(), Controller.class.getMethod("aaa", WebDataBinder.class));
//        List<InvocableHandlerMethod> list = new ArrayList<>();
//        list.add(method);
//
//        FormattingConversionService service = new FormattingConversionService();
//        service.addFormatter(new MyDateFormatter("用 ConversionService 扩展转换功能"));
//        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
//        initializer.setConversionService(service);
//        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(list, initializer);
        // "5. 使用默认ConversionService转换
//        DefaultFormattingConversionService service = new DefaultFormattingConversionService();
        ApplicationConversionService service = new ApplicationConversionService();
        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
        initializer.setConversionService(service);
        ServletRequestDataBinderFactory binderFactory = new ServletRequestDataBinderFactory(null, initializer);

        WebDataBinder binder = binderFactory.createBinder(new ServletWebRequest(request), target, "user");
        binder.bind(new ServletRequestParameterPropertyValues(request));
        System.out.println(target);
    }

    static class Controller{
        @InitBinder
        public void aaa(WebDataBinder binder) {
//            扩展DataBinder 的转换器
            binder.addCustomFormatter(new MyDateFormatter("在 @InitBinder 扩展"));
        }
    }
    static class User {
        @DateTimeFormat(pattern = "yyyy|mm|dd")
        private Date birthday;
        private Address address;

        @Override
        public String toString() {
            return "User{" +
                    "birthday=" + birthday +
                    ", address=" + address +
                    '}';
        }

        public Date getBirthday() {
            return birthday;
        }

        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }

        public Address getAddress() {
            return address;
        }

        public void setAddress(Address address) {
            this.address = address;
        }
    }
    static class Address {
        private String name;

        @Override
        public String toString() {
            return "Address{" +
                    "name='" + name + '\'' +
                    '}';
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    static class MyBean {
        @Override
        public String toString() {
            return "MyBean{" +
                    "a=" + a +
                    ", b='" + b + '\'' +
                    ", c=" + c +
                    '}';
        }

        private int a;
        private String b;
        private Date c;

        public int getA() {
            return a;
        }

        public void setA(int a) {
            this.a = a;
        }

        public String getB() {
            return b;
        }

        public void setB(String b) {
            this.b = b;
        }

        public Date getC() {
            return c;
        }

        public void setC(Date c) {
            this.c = c;
        }


    }
}
